#ifndef __FIBER_H__ 
#define __FIBER_H__

#include <functional>
#include <memory>
#include <ucontext.h>

// #include "thread.h"
#include "log.h"
#include "util.h"

namespace johnsonli
{
	class Fiber : public std::enable_shared_from_this<Fiber>
	{
	public:
		typedef std::shared_ptr<Fiber> ptr;
		
		/// <summary>
		/// 协程状态
		/// </summary>
		enum State
		{
			INIT,		//初始化状态
			HOLD,		//暂停状态
			EXEC,		//执行中状态
			TERM,		//结束状态
			READY,		//可执行状态
			EXCEPT		//异常状态
		};
	public:
		/// <summary>
		/// 无参构造函数
		/// 每个线程第一个协程的构造，主协程
		/// </summary>
		Fiber();

	public:
		 /// <summary>
		 /// 构造函数
		 /// </summary>
		 /// <param name="cb">协程执行函数</param>
		 /// <param name="stacksize">协程栈大小</param>
		 /// <param name="use_caller">Schedule中是否使用主线程</param>
		 Fiber(std::function<void()> cb, size_t stacksize = 0, bool use_caller = false);
		
		 ~Fiber();

		//重置协程函数，并重置状态
		//pre: getState() 为 INIT, TERM, EXCEPT
		//post: INIT
		void reset(std::function<void()> cb);
		
		//将当前协程切换到运行状态， Scheduler调度协程 --> 当前协程
		void swapIn();
		

		/***
		 * @brief: 退出当前线程，当前协程 --> Scheduler调度协程
		 */
		void swapOut();

		 /**
		 * @brief 将当前协程切换到执行状态 主协程-->当前协程
		 */
		void call();

		/**
		 * @brief 将当前协程切换到后台，当前协程-->主协程
		 */
		void back();

		uint64_t getId() const { return m_id; }

		void setState(Fiber::State state) { m_state = state; }
		State getState() const { return m_state; }

	public:
		/// <summary>
		/// 设置当前线程的运行协程
		/// </summary>
		/// <param name="fiber">运行协程</param>
		static void SetThis(Fiber* fiber);

	
		/// <summary>
		/// 返回当前协程
		/// </summary>
		/// <returns>一个全局静态变量 static thread_globle Thread* t_fiber</returns>
		static Fiber::ptr GetThis();
		
		/// <summary>
		/// 返回当前协程的id
		/// </summary>
		/// <returns></returns>
		static uint64_t GetId();

		/// <summary>
		/// 协程切换到后台，并设置为READY状态
		/// 回到Scheduler协程
		/// </summary>
		static void YieldToReadyBySwap();

		/// <summary>
		/// 协程切换到后台，并设置为HOLD状态
		/// 回到Scheduler协程
		/// </summary>
		static void YieldToHoldBySwap();

		/// <summary>
		/// 协程切换到后台，并设置为Ready状态
		/// 回到主协程
		/// </summary>
		static void YieldToReadyByBack();

		/// <summary>
		/// 协程切换到后台，并设置为HOLD状态
		/// 回到主协程
		/// </summary>
		static void YieldToHoldByBack();

		/// <summary>
		/// 返回当前协程的总数量
		/// </summary>
		/// <returns></returns>
		static uint64_t TotalFibers();

		/// <summary>
		/// 协程的工作函数，执行完成返回到Scheduler协程
		/// </summary>
		static void MainFunc();

		/**
		 * @brief 协程执行函数
		 * @post use_caller时有效，Scheduler会使用主线程的时候
		 */
		static void CallerMainFunc();
		
	private:
		uint64_t m_id = 0;           //协程id
		uint32_t m_stacksize = 0;    //协程运行栈大小
		State m_state = INIT;        //协程状态
								     
		ucontext_t m_ctx;            //协程上下文
		void* m_stack = nullptr;     //协程运行栈指针

		std::function<void()> m_cb;	 //协程工作函数
	};
}

#endif // !__FIBER_H__ 

